package com.github.soiff.shadow.plugin.helper;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.github.jknack.handlebars.Options;
import com.github.jknack.handlebars.TagType;
import com.github.soiff.shadow.plugin.SpringPlugin;
import com.github.soiff.shadow.plugin.common.Component;
import com.github.soiff.shadow.plugin.utils.JsonMapper;
import com.github.soiff.shadow.plugin.utils.ThreadVars;
import com.google.common.base.MoreObjects;
import com.google.common.html.HtmlEscapers;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.*;

/**
 * Created by Soiff on 2016/05/20.
 *
 * @author : Soiff
 */
public class InjectHelper implements Helper<String> {

    public final static String directive = "inject";

    final static ObjectMapper mapper = new ObjectMapper();

    @Override
    public CharSequence apply(String compPath, Options options) throws IOException {
        // TODO:
        //   1. compPath = "spring://Shadow:hello"
        //   2. options#hash = {name = "world"}
        boolean isDesignMode = options.get("_DESIGN_MODE_") != null;
        HashMap tempContext = new HashMap();
        if(options.context.model() instanceof Map) {
            tempContext.putAll((Map)options.context.model());
            if(SpringPlugin.isClearInjectNestedContext()) {
                Set cdataKeys = (Set)tempContext.remove("_CDATA_KEYS_");
                if(cdataKeys != null) {
                    Iterator component = cdataKeys.iterator();

                    while(component.hasNext()) {
                        String firstParam = (String)component.next();
                        tempContext.remove(firstParam);
                    }
                }
            }

            if(isDesignMode) {
                tempContext.remove("_COMP_DATA_");
            }
        }

        HashSet cdataKeys1 = new HashSet();
        if(options.hash != null && !options.hash.isEmpty()) {
            tempContext.putAll(options.hash);
            cdataKeys1.addAll(options.hash.keySet());
        }

        if(options.tagType == TagType.SECTION && StringUtils.isNotBlank(options.fn.text())) {
            Map component1 = (Map) JsonMapper.nonEmptyMapper().fromJson(String.valueOf(options.fn()), Map.class);
            if(component1 != null && !component1.isEmpty()) {
                cdataKeys1.addAll(component1.keySet());
                tempContext.putAll(component1);
                if(isDesignMode) {
                    tempContext.put("_COMP_DATA_", HtmlEscapers.htmlEscaper().escape(options.fn.text().trim()));
                }
            }
        }

        if(SpringPlugin.isClearInjectNestedContext()) {
            tempContext.put("_CDATA_KEYS_", cdataKeys1);
        }

        Component component2 = new Component();
        component2.setPath(compPath);
        Object firstParam1 = options.param(0, Boolean.valueOf(true));
        if(firstParam1.equals(Boolean.valueOf(true))) {
            Component paths = SpringPlugin.findComponent(ThreadVars.getAppKey(), compPath);
            if(paths == null) {
                SpringPlugin.log.debug("can\'t find component config for path:{}", compPath);
            } else {
                component2 = paths;
            }
        } else if(firstParam1 instanceof String) {
            component2.setService((String)firstParam1);
        }

        if(isDesignMode) {
            String[] paths1 = compPath.split("/");
            tempContext.put("_COMP_NAME_", MoreObjects.firstNonNull(component2.getName(), paths1[paths1.length - 1]));
        }

        return new Handlebars.SafeString(SpringPlugin.execComponent(component2, tempContext));
    }
}
